package com.lobov.run.yale;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import mpi.MPI;

import com.lobov.containers.MultiPairYale;
import com.lobov.entities.ContainerOfSnipsYale;
import com.lobov.entities.Timer;
import com.lobov.entities.yale.MatrixYale;
import com.lobov.entities.yale.SnipYale;
import com.lobov.utils.Compressor;
import com.lobov.utils.Generator;
import com.lobov.utils.yale.CutterYale;

public class RunMPIYale {
	
	public static void main(String[] args) throws Exception {
		
//		for(double i = 0.1d; i <= 1.01d; i+=0.3d){
//			action(i, false, args);
//		}
//		for(double i = 0.1d; i <= 1.01d; i+=0.3d){
			action(0.2, true, args);
			action(0.2, false, args);
//		}
	}
	
	
	private static void action(double d, boolean c, String[] args) throws Exception {
		int h = 1000; //размер матриц
		int val = 1000;
		int endValue = 6000;
		boolean compress = c;
		double density = d;
		log("Multi core "+ (compress?"cжатый формат":"полный формат ")+ "наполненность матрицы" + (int)(density*100)+ "%" );
		while (val <= endValue) {
		// генерируем матрицу 1
		MatrixYale matrix1 = Generator.generateUnCompressedHorisontalMatrixYale(val,
				val, density);
		// генерируем матрицу 2
		MatrixYale matrix2 = Generator.generateUnCompressedHorisontalMatrixYale(val,
				val, density);
		//МЕТОДЫ ДЛЯ ТЕСТИРОВАНИЯ!!!
		sc1(matrix1, matrix2, val, compress, density, args);
		
		val+=h;
		}
	}

	// генерируем и перемножаем две матрицы
	private static void sc1(MatrixYale matrix1, MatrixYale matrix2, int val, boolean doZip, double density, String[] args)
			throws Exception {
			try {
				MPI.Init(args);
				int rank = MPI.COMM_WORLD.Rank();
				int size = MPI.COMM_WORLD.Size();
				actionTest(matrix1, matrix2, val, rank, size, doZip, density);
			} finally {
				MPI.Finalize();
			}
	}
	
	private static void actionTest(MatrixYale matrix1, MatrixYale matrix2, int val, int rank, int size, boolean compress, double density) throws Exception {
		PrintWriter writer = new PrintWriter("c:\\MPI_TXT\\report.txt", "UTF-8");
		writer.println("The first line");
		writer.println("The second line");
		writer.close();
		// определяем массив для хранения перемножаемых сущностей
 		MultiPairYale[] mps = new MultiPairYale[4];
 		
		// определяем массив для хранения лоскутов после перемножения
		SnipYale[] sps = new SnipYale[4];

		switch (rank) {
		case 0: {
			
			// режем матрицу 2 на лоскуты и кладем в контейнер
			ContainerOfSnipsYale cont = CutterYale.cutMatrixHorizontal(matrix2, 3);

			// определяем массив лоскутов на перемножениеы
			SnipYale[] snips = cont.getSnips();
		
			if(compress){
				matrix1 = Compressor.compressMatrixYale(matrix1);
			}
			
			// заполняем массив перемножаемых сущностей
			for (int i = 0; i < 3; i++) {
				
				if(compress){
					SnipYale s = Compressor.compressSnipYale(snips[i]);
					mps[i] = new MultiPairYale(matrix1, s);	
				} else {
					mps[i] = new MultiPairYale(matrix1, snips[i]);
				}

			}
			Timer timer = new Timer();
			timer.startTimer();
			// отправляем на ноды контейнеры перемножаемых сущностей
			// и ждем ответных лоскутов TODO продумать как удобней получать
			// лоскуты в один массив
			for (int i = 1; i < 3; i++) {
				MPI.COMM_WORLD.Send(mps, i, 2, MPI.OBJECT, i, 100);
				MPI.COMM_WORLD.Recv(sps, i, 2, MPI.OBJECT, i, 100);
			}

			// производим вычисления с первым лоскутом на 0 процессоре
			sps[0] = (SnipYale) mps[0].compute();

			ContainerOfSnipsYale newCont = new ContainerOfSnipsYale(3,
					sps[0].getXlength());
			for (int i = 0; i < 3; i++) {
				newCont.setSnipByIndex(sps[i], i);
			}
			log(val + " X " + val +  "  "  + timer.getTime() + " мс.");
			
//			write_to_file(newCont.toMatrix().toString());
		}
			break;
		case 1: {
			MPI.COMM_WORLD.Recv(mps, 1, 2, MPI.OBJECT, 0, 100);
			sps[1] = (SnipYale) (mps[1].compute());
			MPI.COMM_WORLD.Send(sps, 1, 2, MPI.OBJECT, 0, 100);
		}
			break;
		case 2: {
			MPI.COMM_WORLD.Recv(mps, 2, 2, MPI.OBJECT, 0, 100);
			sps[2] = (SnipYale) (mps[2].compute());
			MPI.COMM_WORLD.Send(sps, 2, 2, MPI.OBJECT, 0, 100);
		}
			break;
		case 3: {
			// DOESN'T WORK !!! :(
		}
			break;
		}
	}
	
	private static void log(String str) throws IOException, InterruptedException  {
		FileWriter writer = new FileWriter("/home/sanix/reportNEW3core.txt", true);
		writer.write(str + "\n");
		System.out.println(str);
		writer.close();
}
	
	
}
